#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/slab.h>

#include <asm/uaccess.h>
#include <asm/io.h>

#define GPX1_CON  0x11000c20
#define GPX1_SIZE 8

struct led_desc{
	unsigned int dev_major;
	struct class *cls;
	struct device *dev;
	void *vir_base;
};

struct led_desc *led_dev;

static int kvalue = 520;

ssize_t chr_drv_open(struct inode *inode,struct file *filp)
{
	printk("----%s----\n",__FUNCTION__);
	return 0;
}
ssize_t chr_drv_read(struct file *filp,char __user *buf,size_t count,loff_t *fpos)
{
	int ret;
	ret=raw_copy_to_user(buf,&kvalue,count);
	if(ret>0)
	{
		printk("copy_to_user failed\n");
		return -EFAULT;
	}

	return 0;
}
ssize_t chr_drv_write(struct file *filp,const char __user *buf,size_t count,loff_t *fpos)
{
	int ret;
	int value;

	ret=raw_copy_from_user(&value,buf,count);
	if(ret>0)
	{
		printk("copy_to_user failed\n");
		return -EFAULT;
	}
	//对灯进行控制
	if(value)
	{
	//	*gpx2data |= (1<<0);
		writel(readl(led_dev->vir_base+4)|(1<<0),led_dev->vir_base+4);
	}
	else
	{
	//	*gpx2data &= ~(1<<0);
		writel(readl(led_dev->vir_base+4)&~(1<<0),led_dev->vir_base+4);
	}

	return 0;
}
ssize_t chr_drv_close(struct inode *inode,struct file *filp)
{
	printk("----%s----\n",__FUNCTION__);
	return 0;
}
const struct file_operations my_fops = {
	.open = chr_drv_open,//对open赋值
	.read = chr_drv_read,
	.write = chr_drv_write,
	.release = chr_drv_close,
};


static int __init chr_dev_init(void)
{
/*	//申请设备号资源
	int ret;
	ret=register_chrdev(dev_major,"chr_dev_test",&my_fops);
	if(ret==0)
	{
		printk("register ok\n");
	}
	else
	{
		printk("register failed\n");
		return -EINVAL;
	}

	devcls = class_create(THIS_MODULE,"chr_cls");
	dev = device_create(devcls,NULL,MKDEV(dev_major,0),NULL,"chr2");

	gpx2conf = ioremap(GPX2_CON,GPX2_SIZE);
	gpx2data = gpx2conf + 1;  //long为四个字节，+1加了四个字节
//初始化输出功能
	*gpx2conf &= ~(0xf<<0);
	*gpx2conf |= (0x1<<0);
*/
	int ret;
	u32 value;
//为结构体开辟空间
	led_dev = kmalloc(sizeof(struct led_desc),GFP_KERNEL);
	if(led_dev==NULL)
	{
		printk(KERN_ERR "malloc failed\n");
		ret=-ENODEV;
	}
//动态申请设备号，并做 出错判断0
	led_dev->dev_major=register_chrdev(0,"led_dev_test",&my_fops);
	if(led_dev->dev_major<0)
	{
		printk(KERN_ERR"register_chrdev failed\n");
		ret=-ENODEV;
		goto err_0;
	}
//创建设备文件，出错判断1 2
	led_dev->cls=class_create(THIS_MODULE,"led_cls");
	if(IS_ERR(led_dev->cls))
	{
		printk(KERN_ERR "class_create failed\n");
		ret=PTR_ERR(led_dev->cls);//将指针出错的具体原因转换成一个出错码
		goto err_1;
	}
	
	led_dev->dev=device_create(led_dev->cls,NULL,MKDEV(led_dev->dev_major,0),NULL,"led%d",0);
	if(IS_ERR(led_dev->dev))
	{
		printk(KERN_ERR "dev_create failed\n");
		ret=PTR_ERR(led_dev->dev);//将指针出错的具体原因转换成一个出错码
		goto err_2;
	}
//硬件初始化	
	led_dev->vir_base=ioremap(GPX1_CON,GPX1_SIZE);
	if(led_dev->vir_base==NULL)
	{
		printk(KERN_ERR "ioremap failed\n");
		ret=-ENOMEM;
		goto err_3;
	}

	value=readl(led_dev->vir_base);
	value &= ~(0xf<<0);
	value |= (0x1<<0);
	writel(value,led_dev->vir_base);
	return 0;

err_3:
	device_destroy(led_dev->cls,MKDEV(led_dev->dev_major,0));
err_2:
	class_destroy(led_dev->cls);
err_1:
	unregister_chrdev(led_dev->dev_major,"led_dev_test");
err_0:
	kfree(led_dev);
	return ret;
}

static void __exit chr_dev_exit(void)
{
	//释放设备号
	iounmap(led_dev->vir_base);
	device_destroy(led_dev->cls,MKDEV(led_dev->dev_major,0));
	class_destroy(led_dev->cls);
	unregister_chrdev(led_dev->dev_major,"chr_dev_test");
	kfree(led_dev);

}

module_init(chr_dev_init);
module_exit(chr_dev_exit);
MODULE_LICENSE("GPL");

